package com.keshi.openplatform.gateway.filters;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.keshi.openplatform.commons.beans.BaseResultBean;
import com.keshi.openplatform.commons.constans.ExceptionDict;
import com.keshi.openplatform.commons.constans.SystemParams;
import com.keshi.openplatform.gateway.feign.CacheService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@Component
public class JwtFilter extends ZuulFilter {
    @Autowired
    private CacheService cacheService;

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }


    /**
     * 理论上它是第一个需要校验的filter
     * @return
     */
    @Override
    public int filterOrder() {
        return 9;
    }

    @Override
    public boolean shouldFilter() {
         return RequestContext.getCurrentContext().sendZuulResponse();
    }

    @Override
    public Object run() throws ZuulException {
        //很简单,拿到用户传递的jwt
        //我们要求用户通过token这个header来传递
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        String jwt = request.getHeader("token");//拿到我们的JWT
        //进行校验
        try {
            //用户可能会多次登陆,或者是在多个设备上登陆,如果我们的平台不允许用户多设备登陆,代表一旦在某个设备上登陆后,之前的token就要失效
            //在此处我们应该要判断当前的用户的最新token和用户传递的token是不是一样.所以我一定要在某个地方保存有用户最新的token
            //我们选择保存在数据库加redis,在这里应该是从redis进行查询看看用户的最新的token是什么
            //校验JWT.如何失败会抛出异常
            Claims body = Jwts.parser().setSigningKey("meiyoumima".getBytes()).parseClaimsJws(jwt).getBody();
            String subject = body.getSubject();
            Object id = body.get("id");
            //如何知道用户最新的token,也就是redis中的key应该和什么有关,我们可以和用户的id或者是名字有关即可
            //我们可以根据用户传递过来的token中的id或者名字去查询一下它对应的最新的token
            String jwtfromRedis = cacheService.getFromRedis(SystemParams.JWT_TOKEN_REDIS_PRE + subject);
            //如果没有异常代表校验成功,直接放行
            if (jwt != null&&!jwt.equals(jwtfromRedis)) {
                //缓存中放的最新的和用户传递的不一致的情况下,就直接扔出异常,给用户返回认证失败
                throw new RuntimeException();
            }
            System.err.println(subject);
            System.err.println(id);
            return null;
        }catch (Exception e){
            //不能访问了
            context.setSendZuulResponse(false);
            HttpServletResponse response = context.getResponse();
            response.setContentType("appliaction/json;charset=utf-8");
            BaseResultBean bean = new BaseResultBean();
            bean.setCode(ExceptionDict.UNLOGIN);
            bean.setMsg("尚未登陆认证");
            try {
                context.setResponseBody(objectMapper.writeValueAsString(bean));
            } catch (JsonProcessingException ex) {
                ex.printStackTrace();
            }
        }

        return null;
    }
}
